package com.ndp.fb.walle.business.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ndp.ec.core.api.DPARobotCoreService;
import com.ndp.ec.core.api.DecisionAction;
import com.ndp.ec.core.model.robot.Attribution;
import com.ndp.ec.core.model.robot.ManualAction;
import com.ndp.fb.constant.CommonConstants;
import com.ndp.fb.enums.admarket.AdMarketStatus;
import com.ndp.fb.enums.robot.OptimizingType;
import com.ndp.fb.exception.CheckedException;
import com.ndp.fb.mongo.api.AdGroupMongoService;
import com.ndp.fb.mongo.api.AdMarketTargetMongoService;
import com.ndp.fb.mongo.api.AdMarketTargetStatsMongoService;
import com.ndp.fb.mongo.api.EcMarketingActionRecordMongoService;
import com.ndp.fb.mongo.api.TargetingService;
import com.ndp.fb.mongo.model.AdForMongo;
import com.ndp.fb.mongo.model.autocreatead.AdMarketTarget;
import com.ndp.fb.rdb.api.FeedRdbService;
import com.ndp.fb.rdb.api.ProductManageRdbService;
import com.ndp.fb.rdb.model.FeedWe;
import com.ndp.fb.rdb.model.User;
import com.ndp.fb.rdb.model.productmanage.ProductManage;
import com.ndp.fb.redis.api.RedisClient;
import com.ndp.fb.walle.business.AdMarketTargetService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Created by Elvis on 2016/6/6.
 */
@Component
public class AdMarketTargetServiceImpl implements AdMarketTargetService {

    private static Logger logger = LoggerFactory.getLogger(AdMarketTargetServiceImpl.class);

    @Reference
    private AdMarketTargetMongoService adMarketTargetRdbService;

    @Reference
    private AdMarketTargetStatsMongoService adMarketTargetStatsMongoService;

    @Reference
    private ProductManageRdbService productManageRdbService;

    @Reference
    private AdGroupMongoService adGroupMongoService;

    @Reference
    private FeedRdbService feedRdbService;

    @Reference
    private TargetingService targetingService;

    @Reference
    private DPARobotCoreService dpaRobotCoreService;

    @Reference
    private AdMarketTargetMongoService adMarketTargetMongoService;
    @Reference
    private EcMarketingActionRecordMongoService ecMarketingActionRecordMongoService;
    @Autowired
    private RedisClient redisClient;

    @Override
    public AdMarketTarget getAdMarketTarget(String id) {
        return adMarketTargetRdbService.findByMarketingId(id.toString());
    }

    @Override
    public String save(AdMarketTarget adMarketTarget) throws CheckedException {
    	String id = adMarketTargetRdbService.save(adMarketTarget);
        try{
            dpaRobotCoreService.createMarketingTarget(id);
        }catch (Exception e){
        	logger.error(e.getMessage(),e);
        	redisClient.delete(CommonConstants.ADMARKETTARGET+id);
        }
        return id;
    }

    @Override
    public void update(AdMarketTarget adMarketTarget) {
        adMarketTargetRdbService.updateAdMarketTarget(adMarketTarget);
        dpaRobotCoreService.updateMarketingTarget(adMarketTarget.getId());
    }

    @Override
    public JSONObject getAdMarketListWithStatsData(JSONObject param, String ticket) {
        JSONObject adMarketListWithStatsData = adMarketTargetStatsMongoService.getAdMarketListWithStatsData(param, ticket);
        if (!CollectionUtils.isEmpty(adMarketListWithStatsData)) {
            JSONArray dataList = adMarketListWithStatsData.getJSONArray("data");
            if (!CollectionUtils.isEmpty(dataList)) {
                dataList.forEach(data -> {
                	JSONObject jsonObject = (JSONObject) data;
                    List<ProductManage> productManages = productManageRdbService.findByProductId(jsonObject.getLong("productId"));
                    jsonObject.put("opStatus", getAdMarketOpStatus(jsonObject));
                    if (!CollectionUtils.isEmpty(productManages)) {
                        // 将产品id转换为产品名称，以便前端进行显示
                        ((JSONObject) data).put("productName", productManages.get(0).getProdName());
                    }
                });
            }
        }
        return adMarketListWithStatsData;
    }
    private String getAdMarketOpStatus(JSONObject jsonObject){
    	String opStatus = "running";
    	 if(redisClient.hasKey(CommonConstants.ADMARKETTARGET+jsonObject.getString("id"))){
         	JSONObject status = (JSONObject)redisClient.get(CommonConstants.ADMARKETTARGET+jsonObject.getString("id"));
         	opStatus = status.getString("status");
         }else{
         	if(jsonObject.getIntValue("status")==AdMarketStatus.FAIL.getCode()){
         		opStatus = "fail";
         	}else if(jsonObject.getIntValue("status")==AdMarketStatus.PAUSE.getCode()){
         		opStatus = "stop";
         	}else{
         		opStatus = "running";
         	}
         }
    	 return opStatus;
    }
    @Override
    public JSONObject getAllAds(JSONObject param) {
        return adGroupMongoService.groupByAdForAdMarketTarget(param);
    }

    @Override
    public JSONObject findAdMarket(String id, User user) {
    	AdMarketTarget adMarketTarget = adMarketTargetRdbService.findByMarketingId(id);
    	JSONObject adM = JSONObject.parseObject(JSONObject.toJSONString(adMarketTarget));
        if (null != adM) {
            List<ProductManage> productManages = productManageRdbService.findByProductId(adM.getLong("productId"));
            if (!CollectionUtils.isEmpty(productManages)) {
                adM.put("productName", productManages.get(0).getProdName());
            }

            FeedWe feedWe = feedRdbService.findFeedWeById(adM.getLong("feedWeId"));
            if (null != feedWe) {
                adM.put("feedWeName", feedWe.getFeedName());
            }

            String[] langs = user.getLanguage().split(CommonConstants.SYMBOL_LINE);
            String lan = langs[0] + CommonConstants.SYMBOL_UNDERLINE + langs[1].toUpperCase();
            JSONObject countryJ = targetingService.getCountry(adM.getString("targetCountry"), lan);
            if (null != countryJ) {
                adM.put("targetCountryName", countryJ.getString(lan + "_name"));
            }
            
            adM.put("opStatus", getAdMarketOpStatus(adM));
        }
        return adM;
    }

    @Override
    public String optimizeAd(JSONObject param) {
        OptimizingType optimizingType = param.getObject("optimizingType", OptimizingType.class);
        Long adId = param.getLong("adId");
        Long dailyBudget = param.getLong("dailyBudget");

        JSONArray attributionStrs = param.getJSONArray("attributions");
        ArrayList<Attribution> attributions = new ArrayList<>();
        attributionStrs.forEach(attributionStr -> {
            Attribution attribution = new Attribution();
            attribution.setOptimizingType(optimizingType);
            attribution.setAttribution(attributionStr.toString());
            attribution.setValue(dailyBudget);
            attributions.add(attribution);
        });
        String adMarketTargetId = param.getString("adMarketTargetId");
        AdMarketTarget adMarketTarget = adMarketTargetRdbService.findByMarketingId(adMarketTargetId);
        ManualAction decisionAction = new ManualAction(optimizingType, attributions);
        String uuid = UUID.randomUUID().toString();
        decisionAction.setId(uuid);
        String jobId = "OptimizeAd_Job_" + uuid;
        decisionAction.setStatusKey(jobId);
        decisionAction.setAdId(adId);
        decisionAction.setValue(dailyBudget);
        decisionAction.setMarketTargetId(adMarketTarget.getId());

        List<DecisionAction> decisionActions = new ArrayList() {{
            add(decisionAction);
        }};
        
        // 用来保存Job的状态和失败原因等
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("status", "init");
        JSONObject object = new JSONObject();
    	object.put("status", "optimizing");
    	if(!redisClient.setNx(CommonConstants.ADMARKETTARGET+adMarketTarget.getId(), object, 1, TimeUnit.HOURS.name())){
    		jsonObject.put("status", "fail");
            jsonObject.put("message", "admarkettarget updating");
        }else if (OptimizingType.UP_BUDGET.equals(optimizingType)) {
        	// 如果是调高预算，则要判断是否还有足够的预算
            List<AdForMongo> adForMongos = adGroupMongoService.findAdByAdMarketTargetId(adMarketTargetId, "ad_id", "effective_status", "adSet.daily_budget");
            if (!CollectionUtils.isEmpty(adForMongos)) {
                List<AdForMongo> adForMongosExceptTargetAd = new ArrayList<>();
                adForMongos.forEach(adForMongo -> {
                    if (!adId.equals(adForMongo.getAd_id())) {
                        adForMongosExceptTargetAd.add(adForMongo);
                    }
                });
                Long adBudget = dpaRobotCoreService.getAdBudget(adForMongosExceptTargetAd);
                if ((adBudget + dailyBudget) > adMarketTarget.getDayBudget()) {
                    jsonObject.put("status", "fail");
                    jsonObject.put("message", "Insufficient budget.");
                }
            }
        }
        redisClient.set(jobId, JSON.toJSONString(jsonObject), 1, TimeUnit.DAYS.name());
        if (!"fail".equals(jsonObject.getString("status"))) {
            try {
                dpaRobotCoreService.performDecision(decisionActions, adMarketTarget);
            } catch (Exception e) {
                logger.error("调用决策执行失败，decisionAction:{},adMarketTarget:{}", decisionAction, adMarketTarget, e);
            }
        }else{
        	redisClient.delete(CommonConstants.ADMARKETTARGET+adMarketTarget.getId());
        }
        return jobId;
    }

    @Override
    public Map<String, Object> getJobStatus(JSONObject param) {
        String jobId = param.getString("jobId");
        Object value = redisClient.get(jobId);
        Map<String, Object> result = new HashMap<>();
        if (null == value) {
            result.put("status", "timeout");
        } else {
            result.putAll(JSON.parseObject(value.toString()));
        }
        return result;
    }

    @Override
    public void updateAdMarket(String id, Integer status, String attribution) {
    	try {
			dpaRobotCoreService.stopMarketingTarget(id, attribution);
		} catch (CheckedException e) {
			logger.error(e.getMessage(),e);
		}
        adMarketTargetMongoService.updateAdMarketTargetStatus(id,status,attribution);
    }

	@Override
	public JSONArray getLogs(String id) {
		return ecMarketingActionRecordMongoService.getLogs(id);
	}


}
